﻿using SLNGP.Common.Extensions;
using SLNGP.Core.Genes;
using SLNGP.Core.GeneticPrograms;
using SLNGP.Core.Individuals;
using SLNGP.Core.SecondaryStrategies;
using Enumerable = System.Linq.Enumerable;
using System.Linq;

namespace SLNGP.Core.GeneticOpearators
{
    public class BasicPointMutation : GeneticOpearator, IMutationGeneticOpearator
    {
        public override void Execute()
        {
            var individuals =
                Parent.LastRunResults.LastGeneration.Where(
                    i => (SelectionMarkers)i.SelectionMarker == SelectionMarkers.Mutation);
            foreach (IIndividual individual in individuals)
            {
                Parent.LastRunResults.CurrentGeneration.Add(individual);
                bool _foundNewMutation = false;
                while (!_foundNewMutation)
                {
                    IIndividual newIndividual = GetNewMutation(individual);
                    if (Parent.LastRunResults.CurrentGeneration.TryAddUnique(newIndividual))
                        _foundNewMutation = true;
                }
            }
        }

        private IIndividual GetNewMutation(IIndividual individual)
        {
            var newIndividual = individual.CloneChild();
            var allGenes = newIndividual.AllGenes.ToArray();
            int mutationIndex = Parent.GetStrategy<IRandomProvider>().Random(0, allGenes.Length - 1);
            IGene oldGene = allGenes[mutationIndex];
            IGene newGene = Parent.GetStrategy<ISelectRandomGeneDefinition>().SelectRandomDefinition().Create();
            oldGene.ReplaceWith(newGene);

            if (newGene.IsValid == false)
                newGene.Fix();
            return newIndividual;
        }
    }
}